#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "ToolManager.h"
#include "BasicFileReader.h"
#include "include.h"

#define TIME_BETWEEN_POSITIONS 5000.0/(double)CLOCKS_PER_SEC

ToolManager::ToolManager(char * filename, char * saveFile)
{
	tileList = new TileList();
	currentTile = NULL;
	leftClickDepressed = false;
	leftClickWasDepressed = false;
	rightClickDepressed = false;
	rightClickWasDepressed = false;
	leftArrowDepressed = false;
	leftArrowWasDepressed = false;
	rightArrowDepressed = false;
	rightArrowWasDepressed = false;
	saveKeyDepressed = false;
	saveKeyWasDepressed = false;
	savePoseKeyDepressed = false;
	savePoseKeyWasDepressed = false;
	lockKeyDepressed = false;
	lockKeyWasDepressed = false;
	displayKeyDepressed = false;
	displayKeyWasDepressed = false;
	upKeyDepressed = false;
	upKeyWasDepressed = false;
	downKeyDepressed = false;
	downKeyWasDepressed = false;
	currentPose = 0;
	
	selectedBone = NULL;
	textureManager = new TextureManager();
	this->saveFile = saveFile;
	LoadFile(filename);
	if(!skeleton)
		skeleton = new Skeleton(Vector2D(10,18));
}
ToolManager::~ToolManager()
{
	if(skeleton)
	{
		delete(skeleton);
		skeleton= NULL;
	}
	if(tileList)
	{
		delete(tileList);
		tileList = NULL;
	}
}

int ToolManager::GetElementType(char * element)
{
	if(strcmp(element, "texture")==0)
		return TEXTURE_TYPE;
	if(strcmp(element, "boundingbox")==0)
		return BOUNDING_BOX_TYPE;	
	if(strcmp(element,"pose")==0)
		return POSE_TYPE;
	return -1;
}
Bone * ToolManager::ReadBone(Bone * parent, char * tag, int * pos)
{
	printf("ReadBone\n");
	char * textureName = BasicFileReader::ReadNextString(tag, pos);
	Vector2D * textureVertices = BasicFileReader::ReadNextVectorArray(4,tag,pos);

	Vector2D temp = textureVertices[0];
	textureVertices[0] = textureVertices[1];
	textureVertices[1] = textureVertices[2];
	textureVertices[2] = textureVertices[3];
	textureVertices[3] = temp;
	
	Vector2D size = BasicFileReader::ReadNextCoordinate(tag,pos);
	float temp2 = size.x;
	size.x = size.y;
	size.y = temp2;
	float tbShift = BasicFileReader::ReadNextFloat(tag,pos);
	Vector2D orientation = BasicFileReader::ReadNextCoordinate(tag,pos);
	
	printf("texture name = %s\n", textureName);
	printf("Done reading bone\n");
	return new Bone(parent, orientation.y*3.14159/180, orientation.x, tbShift, new TextureBox(new Tile(textureManager, textureName, textureVertices),size));
}
Bone * ToolManager::HandlePoseTag(Bone * parent, char * tag, int * pos)
{
	//read the pose and build our starting skeleton	
	printf("HandlePoseTag\n");
	Bone * head = ReadBone(parent,tag, pos);
	int numOutgoingBones = BasicFileReader::ReadNextInt(tag,pos);
	
	printf("reading %d outgoing bones\n", numOutgoingBones);
	BoneList * list = new BoneList();
	for(int i=0; i < numOutgoingBones; i++)
	{
		list->Add(HandlePoseTag(head, tag,pos));
	}
	List<Bone> * search = list->head;
	while(search)
	{
		head->AddBone(search->payload);
		search = search->next;
	}
	printf("Done HandlePoseTag\n");
	return head;
}
void ToolManager::LoadFile(char * fileName)
{
	FILE * fptr = NULL;
	printf("Opening file\n");
	if(!(fptr = fopen(fileName, "r")))
	{
		printf("Level file %s is new\n",fileName);
		return;
	}
	printf("File is open\n");
	char * tag;
	char * textureName;
	while((tag = BasicFileReader::GetNextTag(fptr)) != NULL)
	{
		printf("TAG: %s\n", tag);
		//read through the tag, one element at a time
		int pos = 0;		
		char * element = BasicFileReader::GetNextElement(tag, &pos);
		
		
		printf("ELEMENT: %s\n", element);
		//this is the tag's name. Use this to decide how to handle
		//the other parameters
		
		switch(GetElementType(element))
		{
			case TEXTURE_TYPE: 
				textureName = BasicFileReader::ReadNextString(tag, &pos);
				break;
			case BOUNDING_BOX_TYPE:
			{
				Vector2D * vertices = BasicFileReader::ReadNextVectorArray(4,tag, &pos);
				Tile * tile = new Tile(textureManager, textureName, vertices);
				tileList->Add(tile);
				currentTile = tileList->head;
			}
				break;
			case POSE_TYPE:
				skeleton = new Skeleton(Vector2D(10,18),HandlePoseTag(NULL,tag, &pos));
				break;
		}
			
		if(element != NULL)
			free(element);
		element = NULL;
		if(tag != NULL)
			free(tag);
		tag = NULL;
	}
	fclose(fptr);
		
}
void ToolManager::PrepareFrame()
{
	float currentTime = (float)clock()/(float)CLOCKS_PER_SEC;
	float elapsedTime = currentTime - lastThoughtTimestamp;

	if(elapsedTime >= TIME_BETWEEN_POSITIONS)
	{
		lastThoughtTimestamp = currentTime;	
	}
	else
	{
		return;
	}
	
	for(;elapsedTime >= TIME_BETWEEN_POSITIONS; elapsedTime -= TIME_BETWEEN_POSITIONS)
	{
		float thisTime = TIME_BETWEEN_POSITIONS;
		if(elapsedTime < TIME_BETWEEN_POSITIONS)
			thisTime = elapsedTime; 
	
		thisTime /= 2.0;

		HandleUserInput();
		mouse.Think();
	}
}
void ToolManager::Draw()
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0,20,0,20, -1, 1);	
	
	glColor3f(1,1,1);
	glMatrixMode(GL_MODELVIEW);	
	glPushMatrix();
	glLoadIdentity();
	//draw skeleton here
	skeleton->Draw();
	glPopMatrix();	
}
void ToolManager::SetNormalUserInput(unsigned char key, int modifier, bool isDepressed)
{
	printf("key =%d\n",key);
	if(1)
	{
		if(modifier == GLUT_ACTIVE_CTRL)
		{
			printf("Active ctrl\n");
			switch(key)
			{
				case 19:  saveKeyDepressed = isDepressed;break;
				case 16: savePoseKeyDepressed = isDepressed;break;
				case 12: lockKeyDepressed = isDepressed;break;
				case 4: displayKeyDepressed = isDepressed;break;
			}	
		}
		else
		{
			
			switch(key)
			{
			}	
		}
	}
}
void ToolManager::SetUserInput(int key, int modifier, bool isDepressed)
{
	switch(key)
	{
		case GLUT_KEY_UP: upKeyDepressed = isDepressed; break;
		case GLUT_KEY_DOWN: downKeyDepressed = isDepressed; break;
		case GLUT_KEY_RIGHT: rightArrowDepressed = isDepressed; break;
		case GLUT_KEY_LEFT: leftArrowDepressed = isDepressed; break;
	}
}
void ToolManager::SetUserInput(int key, bool isDepressed, float x, float y)
{
	switch(key)
	{
		case GLUT_RIGHT_BUTTON: rightClickDepressed = isDepressed; break;
		case GLUT_LEFT_BUTTON: leftClickDepressed = isDepressed; break;
	}
}
void ToolManager::SetPassiveMouse(float x, float y)
{
	mouse.SetPosition(x,y, Vector2D(1,1));
}	
void ToolManager::SetActiveMouse(float x, float y)
{
	mouse.SetPosition(x,y,Vector2D(1,1));
}

void ToolManager::HandleUserInput()
{
	
	if(lockKeyDepressed && !lockKeyWasDepressed)
	{
		skeleton->ToggleLock();	
	}
	if(displayKeyDepressed && !displayKeyWasDepressed)
	{
		skeleton->ToggleDisplay();
	}
	if(leftArrowDepressed && !leftArrowWasDepressed)
	{
		if(selectedBone)
		{	
			selectedBone->RotateAntiClockwise();
		}
	}
	if(rightArrowDepressed && !rightArrowWasDepressed)
	{
		if(selectedBone)
		{	
			selectedBone->RotateClockwise();
		}
	}
	if(upKeyDepressed && !upKeyWasDepressed)
	{
		if(selectedBone && tileList)
		{	
			if(currentTile)
			{
				currentTile = currentTile->next;
			}
			if(!currentTile)
			{
				currentTile = tileList->head;
			}
			if(currentTile)
			{
				selectedBone->SetTile(currentTile->payload);
			}
		}
	}
	if(rightClickDepressed && !rightClickWasDepressed)
	{
		Bone * bone = skeleton->Click(&mouse);
		bone->RemoveMe();
	}
	if(leftClickDepressed && !leftClickWasDepressed)
	{
		Vector2D mPoint = mouse.GetPosition();
		//mPoint.x = (mPoint.x + 100)/2.0;
		//mPoint.y = (mPoint.y + 100)/2.0;
		printf("innerclick = (%f,%f)\n", mPoint.x,mPoint.y);
		LeftClick();
		
	}
	if(!leftClickDepressed && leftClickWasDepressed)
	{
	}
	if(leftClickDepressed && leftClickWasDepressed)
	{
		LeftDrag();
	}
	if(saveKeyDepressed && !saveKeyWasDepressed)
	{
		SaveData();	
	}
	if(savePoseKeyDepressed && !savePoseKeyWasDepressed)
	{
		SavePose();	
	}
	lockKeyWasDepressed = lockKeyDepressed;
	displayKeyWasDepressed = displayKeyDepressed;
	leftClickWasDepressed = leftClickDepressed;
	rightClickWasDepressed = rightClickDepressed;
	saveKeyWasDepressed = saveKeyDepressed;
	savePoseKeyWasDepressed = savePoseKeyDepressed;
	upKeyWasDepressed = upKeyDepressed;
	downKeyWasDepressed = downKeyDepressed;
	leftArrowWasDepressed = leftArrowDepressed;
	rightArrowWasDepressed = rightArrowDepressed;
}
void ToolManager::LeftClick()
{
	//if we click on an endpoint, select that bone.
	Bone * lastSelectedBone = selectedBone;
	selectedBone = skeleton->Click(&mouse);
	
	if(!selectedBone && lastSelectedBone)
	{
		lastSelectedBone->AddBone(new Bone(lastSelectedBone, 
										Vertex(Vector2D(mouse.GetPosition()-skeleton->GetHeadPosition())),
										new TextureBox()));
	}
}
void ToolManager::LeftDrag()
{
	if(selectedBone)
	{
		selectedBone->Drag(skeleton->GetHeadPosition(), &mouse);
	}
}

void ToolManager::SaveData()
{
	//write skeleton file here
	FILE * fptr = NULL;
	if(!(fptr=fopen(saveFile,"w")))
	{
		printf("Failed to open %s\n", saveFile);
		return;
	}
	fprintf(fptr,"<size,1.0,1.0>\n");
	fprintf(fptr,"<pose,%s>",skeleton->GetTag());
	fclose(fptr);
	fptr = NULL;
}
void ToolManager::SavePose()
{
	//write skeleton file here
	FILE * fptr = NULL;
	char  fileName[15];
	sprintf(fileName,"pose%d.pos",currentPose);
	currentPose++;
	
	if(!(fptr=fopen(fileName,"w")))
	{
		printf("Failed to open %s\n", fileName);
		return;
	}
	fprintf(fptr,"<pose,%s>",skeleton->GetPose());
	fclose(fptr);
	fptr = NULL;
}
